Parking Availability Near Places of Interest in Melbourne
Authored by: Samiha Haque
Duration: 90 mins
Level: Intermediate
Pre-requisite Skills: Python, TF-IDF Vectoriser, Cosine Similarity, Haversine Distance, Geographical Coordinate Handling, Folium Maps
Scenario

As a resident of Melbourne, I want to input my current location and the places of interest I plan to visit so that I can identify the nearest parking bays to these locations, helping me better understand the parking availability and proximity to my chosen destinations.

What this use case will teach you

At the end of this use case you will:

  • Learn to work with categorical locations and geolocations using geopy.
  • Learn foundational NLP techniques, including corpus creation, using regular expressions to remove unnecessary symbols, tokenization, stopword removal, and applying TF-IDF vectorization.
  • Learn to use cosine similarity and haversine distance.
  • Learn to plot multiple geolocations on a map using folium.
  • Learn to display multiple maps on different tabs using folium.
Accessible Parking and Digital Connectivity in Melbourne

The ninth Sustainable Development Goal (SDG) of the City of Melbourne, "Industry, Innovation, and Infrastructure," emphasizes the development of affordable and equitable transport infrastructure for all. This includes ensuring the availability and adequacy of parking facilities around popular places of interest.

In this use case, users can input their current location and desired places of interest. The code will then identify up to 10 top matches within a 2km radius of the user’s location. For each suggested place, a map will display all parking bays within a 200m radius. This functionality will help users plan their journeys more effectively by providing them with a visual overview of parking options near their destinations. It ensures that users can easily find convenient parking spots, enhancing their overall travel experience.

This use case also aligns with one of the eight key priorities of the Economic Development Strategy 2031 for the City of Melbourne: creating a digitally connected city. By leveraging smart technology and connectivity, this initiative supports Melbourne’s vision of becoming a knowledge-enabled, smart city, adapting to modern connectivity needs and enhancing urban infrastructure.

Datasets used
  • Landmarks and places of interest, including schools, theatres, health services, sports facilities, places of worship, galleries and museums

This dataset mainly contains the theme, sub_theme, feature_name and coordinates of various places of interest throughout the city of Melbourne. This dataset is used to create the corpus and filter suggested places of interest based on user inputs, identifying options within a 2km radius of the user’s location. This dataset is imported from Melbourne Open Data website, using API V2.1.

  • On-street Parking Bays

This dataset contains the roadsegmentid, kerbsideid, roadsegmentdescription, latitude, longitude and last updated details of on-street parking bays throughout the city of Melbourne. The longitude and latitude features of this dataset are used to identify parking bays within a 200m radius of each suggested place of interest. This dataset is imported from Melbourne Open Data website, using API V2.1.

In [1]:
import requests
import pandas as pd
import numpy as np
from io import StringIO
import seaborn as sns
import matplotlib.pyplot as plt
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
import re
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import folium
from folium.plugins import MarkerCluster
import math
import geopy
from geopy.geocoders import Nominatim
from IPython.display import display, HTML
import ipywidgets as widgets
import warnings
warnings.filterwarnings("ignore")
In [2]:
nltk.download('stopwords')
nltk.download('punkt')
[nltk_data] Downloading package stopwords to
[nltk_data]     /Users/samihahaque/nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
[nltk_data] Downloading package punkt to
[nltk_data]     /Users/samihahaque/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
Out[2]:
True

Loading the datasets using API 2.1v¶

In [3]:
base_url='https://data.melbourne.vic.gov.au/api/explore/v2.1/catalog/datasets/'
dataset_id='landmarks-and-places-of-interest-including-schools-theatres-health-services-spor'


url=f'{base_url}{dataset_id}/exports/csv'
params={'select':'*','limit':-1,'lang':'en','timezone':'UTC'}

response=requests.get(url,params=params)

if response.status_code==200:
    url_content=response.content.decode('utf-8')
    places=pd.read_csv(StringIO(url_content),delimiter=';')
    print(places.head(10))
else:
    print(f'Request failed with status code {response.status_code}')
              theme           sub_theme                     feature_name  \
0  Place of Worship              Church                St Francis Church   
1  Place of Worship              Church                  St James Church   
2  Place of Worship              Church        St Mary's Anglican Church   
3  Place of Worship              Church                     Scots Church   
4  Place of Worship              Church      St Michael's Uniting Church   
5  Place of Worship              Church            Greek Orthodox Church   
6  Place of Worship              Church          North Melbourne Uniting   
7  Place of Worship              Church  South Yarra Presbyterian Church   
8  Place of Worship           Synagogue         East Melbourne Synagogue   
9         Transport  Transport Terminal                Port of Melbourne   

                          co_ordinates  
0  -37.8118847831837, 144.962422614541  
1  -37.8101281201969, 144.952468571683  
2  -37.8031663672997, 144.953761537074  
3   -37.8145687802664, 144.96855105335  
4  -37.8143851324913, 144.969174036096  
5  -37.8088064667555, 144.978259089269  
6  -37.8035538471344, 144.947671538375  
7   -37.8407473645397, 144.98562699348  
8    -37.809113728917, 144.97422190954  
9   -37.8137384362671, 144.91753432375  
In [4]:
base_url='https://data.melbourne.vic.gov.au/api/explore/v2.1/catalog/datasets/'
dataset_id='on-street-parking-bays'


url=f'{base_url}{dataset_id}/exports/csv'
params={'select':'*','limit':-1,'lang':'en','timezone':'UTC'}

response=requests.get(url,params=params)

if response.status_code==200:
    url_content=response.content.decode('utf-8')
    parking_bays=pd.read_csv(StringIO(url_content),delimiter=';')
    print(parking_bays.head(10))
else:
    print(f'Request failed with status code {response.status_code}')
   roadsegmentid kerbsideid  \
0          22730        NaN   
1          22730        NaN   
2          20013       5701   
3          20013      23444   
4          22268        NaN   
5          22295        NaN   
6          22295        NaN   
7          22295        NaN   
8          21108        NaN   
9          20950        NaN   

                              roadsegmentdescription   latitude   longitude  \
0  Park Street between Mason Street and Randall P... -37.836245  144.982021   
1  Park Street between Mason Street and Randall P... -37.835800  144.982115   
2  Lonsdale Street between William Street and Kin... -37.814238  144.955451   
3  Lonsdale Street between William Street and Kin... -37.814271  144.955334   
4  Clowes Street between Anderson Street and Wals... -37.830568  144.984713   
5  Anderson Street between Domain Road and Acland... -37.833607  144.983763   
6  Anderson Street between Domain Road and Acland... -37.833657  144.983753   
7  Anderson Street between Domain Road and Acland... -37.833817  144.983720   
8  Courtney Street between Queensberry Street and... -37.803262  144.955425   
9  Queensberry Street between Capel Street and Ho... -37.803515  144.954739   

  lastupdated  
0  2022-08-31  
1  2022-08-31  
2  2023-10-02  
3  2023-10-02  
4  2022-08-31  
5  2022-08-31  
6  2022-08-31  
7  2022-08-31  
8  2022-08-31  
9  2022-08-31  

coordinates function to return latitude and longitude given any categorical location¶

In [5]:
def coordinates(location):
    geolocator = Nominatim(user_agent="geocoding")
    loc = geolocator.geocode(location)
    if loc:
        return loc.latitude, loc.longitude
    else:
        raise Exception("Geocoding failed")

haversine function to return the haversine distance given a pair of latitudea and longitudes¶

In [6]:
def haversine(lat1, lon1, lat2, lon2):
    R = 6371  # Radius of Earth in kilometers
    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = math.sin(dlat / 2) ** 2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2) ** 2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    distance = R * c
    return distance

create_map function to create map and markers¶

In [7]:
def create_map(map_display,df,popup,color,marker=False):
    if marker:
        marker_cluster = MarkerCluster().add_to(map_display)


    # Add markers for each location
        for index, row in df.iterrows():

            folium.Marker(location=[row['latitude'], row['longitude']], 
                          popup=row[popup],
                          icon=folium.Icon(color),
                          icon_size=(3, 3)).add_to(marker_cluster)
    else:
        for index, row in df.iterrows():

            folium.Marker(location=[row['latitude'], row['longitude']], 
                          popup=row[popup],
                          icon=folium.Icon(color),
                          icon_size=(3, 3)).add_to(map_display)

    

    return map_display

Cleaning Places dataset¶

In [8]:
places
Out[8]:
theme sub_theme feature_name co_ordinates
0 Place of Worship Church St Francis Church -37.8118847831837, 144.962422614541
1 Place of Worship Church St James Church -37.8101281201969, 144.952468571683
2 Place of Worship Church St Mary's Anglican Church -37.8031663672997, 144.953761537074
3 Place of Worship Church Scots Church -37.8145687802664, 144.96855105335
4 Place of Worship Church St Michael's Uniting Church -37.8143851324913, 144.969174036096
... ... ... ... ...
237 Education Centre School - Primary and Secondary Education Melbourne Girls Grammar School -37.8315364518803, 144.985089428348
238 Retail Department Store Myer -37.8135911985281, 144.963855087868
239 Retail Department Store David Jones -37.8133127260638, 144.964373486798
240 Health Services Medical Services Mercy Private Hospital -37.811896809802, 144.984435746587
241 Mixed Use Retail/Office/Carpark ANZ 'Gothic' Bank -37.8161580666029, 144.961673719242

242 rows × 4 columns

In [9]:
places.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 242 entries, 0 to 241
Data columns (total 4 columns):
 #   Column        Non-Null Count  Dtype 
---  ------        --------------  ----- 
 0   theme         242 non-null    object
 1   sub_theme     242 non-null    object
 2   feature_name  242 non-null    object
 3   co_ordinates  242 non-null    object
dtypes: object(4)
memory usage: 7.7+ KB
In [10]:
places.shape
Out[10]:
(242, 4)
In [11]:
places.isna().sum()
Out[11]:
theme           0
sub_theme       0
feature_name    0
co_ordinates    0
dtype: int64
In [12]:
places['theme'].value_counts()
Out[12]:
theme
Leisure/Recreation                      63
Place Of Assembly                       40
Place of Worship                        31
Transport                               26
Community Use                           21
Education Centre                        13
Mixed Use                               11
Health Services                         11
Office                                  11
Purpose Built                            4
Vacant Land                              3
Retail                                   3
Residential Accommodation                2
Specialist Residential Accommodation     1
Warehouse/Store                          1
Industrial                               1
Name: count, dtype: int64
In [13]:
places['sub_theme'].value_counts()
Out[13]:
sub_theme
Informal Outdoor Facility (Park/Garden/Reserve)    37
Church                                             30
Railway Station                                    23
Art Gallery/Museum                                 19
Theatre Live                                       15
Major Sports & Recreation Facility                 14
Public Buildings                                   13
Office                                             11
Public Hospital                                     7
Retail/Office/Carpark                               5
Tertiary (University)                               4
Primary Schools                                     4
Outdoor Recreation Facility (Zoo, Golf Course)      4
Function/Conference/Exhibition Centre               4
Indoor Recreation Facility                          3
Police Station                                      3
Private Hospital                                    3
Retail/Office                                       3
Dwelling (House)                                    2
Visitor Centre                                      2
Private Sports Club/Facility                        2
School - Primary and Secondary Education            2
Department Store                                    2
Retail/Office/Residential/Carpark                   2
Observation Tower/Wheel                             2
Film & RV Studio                                    2
Secondary Schools                                   2
Synagogue                                           1
Cemetery                                            1
Transport Terminal                                  1
Bridge                                              1
Aquarium                                            1
Industrial (Manufacturing)                          1
Cinema                                              1
Current Construction Site - Commercial              1
Casino                                              1
Retail                                              1
Library                                             1
Fire Station                                        1
Government Building                                 1
Retail/Residential                                  1
Gymnasium/Health Club                               1
Vacant Land - Undeveloped Site                      1
Store Yard                                          1
Further Education                                   1
Current Construction Site                           1
Marina                                              1
Hostel                                              1
Medical Services                                    1
Name: count, dtype: int64
In [14]:
for i in places['theme'].unique():
    if len(places.loc[places['theme']==i].value_counts())<5:
        print(places.loc[places['theme']==i])
        print("------------------------------------------")
           theme                               sub_theme  \
23   Vacant Land          Vacant Land - Undeveloped Site   
118  Vacant Land               Current Construction Site   
205  Vacant Land  Current Construction Site - Commercial   

                                feature_name  \
23   Melbourne International Karting Complex   
118                             Harbour Town   
205                   Railway Good Shed No 2   

                            co_ordinates  
23   -37.8310746380616, 144.913822928701  
118  -37.8139256326845, 144.938123825625  
205  -37.8211371302179, 144.951378883631  
------------------------------------------
             theme         sub_theme                            feature_name  \
33   Purpose Built  Film & RV Studio                    Central City Studios   
117  Purpose Built  Film & RV Studio  Channel 7 - Melbourne Broadcast Centre   
198  Purpose Built            Casino             Crown Entertainment Complex   
233  Purpose Built          Aquarium                      Melbourne Aquarium   

                            co_ordinates  
33   -37.8142318521296, 144.935655305362  
117   -37.8158572333481, 144.94582326909  
198  -37.8235761092516, 144.957312880653  
233  -37.8209627824685, 144.958425696055  
------------------------------------------
                                   theme sub_theme  \
37  Specialist Residential Accommodation    Hostel   

                         feature_name                         co_ordinates  
37  The Mission To Seafarers Victoria  -37.8224995970811, 144.951254841448  
------------------------------------------
                         theme         sub_theme      feature_name  \
85   Residential Accommodation  Dwelling (House)      Bishopscourt   
133  Residential Accommodation  Dwelling (House)  Government House   

                            co_ordinates  
85    -37.8132921649416, 144.98350690799  
133  -37.8275635886174, 144.976655130464  
------------------------------------------
               theme   sub_theme                     feature_name  \
146  Warehouse/Store  Store Yard  Melbourne Wholesale Fish Market   

                            co_ordinates  
146  -37.8083471006041, 144.930613255612  
------------------------------------------
      theme         sub_theme           feature_name  \
179  Retail            Retail  Queen Victoria Market   
238  Retail  Department Store                   Myer   
239  Retail  Department Store            David Jones   

                            co_ordinates  
179  -37.8075002018073, 144.957158515056  
238  -37.8135911985281, 144.963855087868  
239  -37.8133127260638, 144.964373486798  
------------------------------------------
          theme                   sub_theme feature_name  \
225  Industrial  Industrial (Manufacturing)        Kraft   

                            co_ordinates  
225  -37.8262313085528, 144.923475698195  
------------------------------------------
In [15]:
drop_themes=['Vacant Land','Purpose Built','Specialist Residential Accommodation','Residential Accommodation','Warehouse/Store','Industrial']
places=places[~places['theme'].isin(drop_themes)]
In [16]:
print(places.shape)
places.head()
(230, 4)
Out[16]:
theme sub_theme feature_name co_ordinates
0 Place of Worship Church St Francis Church -37.8118847831837, 144.962422614541
1 Place of Worship Church St James Church -37.8101281201969, 144.952468571683
2 Place of Worship Church St Mary's Anglican Church -37.8031663672997, 144.953761537074
3 Place of Worship Church Scots Church -37.8145687802664, 144.96855105335
4 Place of Worship Church St Michael's Uniting Church -37.8143851324913, 144.969174036096
In [17]:
co_ord_list = places['co_ordinates'].str.split(", ", expand=True)
places.loc[:, 'latitude'] = pd.to_numeric(co_ord_list[0])
places.loc[:, 'longitude'] = pd.to_numeric(co_ord_list[1])
In [18]:
places.drop(columns='co_ordinates',axis=1,inplace=True)
places.reset_index(drop=True, inplace=True)
In [19]:
for i in places.columns[:-2]:
    places.loc[:,i]=places[i].str.lower()
places.head()
Out[19]:
theme sub_theme feature_name latitude longitude
0 place of worship church st francis church -37.811885 144.962423
1 place of worship church st james church -37.810128 144.952469
2 place of worship church st mary's anglican church -37.803166 144.953762
3 place of worship church scots church -37.814569 144.968551
4 place of worship church st michael's uniting church -37.814385 144.969174

Creating the "corpus" column¶

In [20]:
corpus=places.loc[:,'theme']+" "+places.loc[:,'sub_theme']+" "+places.loc[:,'feature_name']
places.loc[:,'corpus']=corpus
In [21]:
pattern = r'[^a-zA-Z0-9\s]'
places.loc[:,'corpus'] = places['corpus'].str.replace(pattern, ' ', regex=True)
# places.loc[:,'corpus']=places['corpus'].str.replace(r'\s+', ' ', regex=True).str.strip()
In [22]:
places.loc[:,'corpus_token']=places['corpus'].apply(word_tokenize)
In [23]:
stop_words=stopwords.words('english')
lst=[]
for i in range(len(places['corpus_token'])):
    st=""
    for j in places.loc[i,'corpus_token']:
        if j not in stop_words:
            st+=j+" "
    
    lst.append(st[:-1])
In [24]:
places.loc[:,'corpus_clean']=lst
places
Out[24]:
theme sub_theme feature_name latitude longitude corpus corpus_token corpus_clean
0 place of worship church st francis church -37.811885 144.962423 place of worship church st francis church [place, of, worship, church, st, francis, church] place worship church st francis church
1 place of worship church st james church -37.810128 144.952469 place of worship church st james church [place, of, worship, church, st, james, church] place worship church st james church
2 place of worship church st mary's anglican church -37.803166 144.953762 place of worship church st mary s anglican church [place, of, worship, church, st, mary, s, angl... place worship church st mary anglican church
3 place of worship church scots church -37.814569 144.968551 place of worship church scots church [place, of, worship, church, scots, church] place worship church scots church
4 place of worship church st michael's uniting church -37.814385 144.969174 place of worship church st michael s uniting c... [place, of, worship, church, st, michael, s, u... place worship church st michael uniting church
... ... ... ... ... ... ... ... ...
225 education centre school - primary and secondary education melbourne girls grammar school -37.831536 144.985089 education centre school primary and secondar... [education, centre, school, primary, and, seco... education centre school primary secondary educ...
226 retail department store myer -37.813591 144.963855 retail department store myer [retail, department, store, myer] retail department store myer
227 retail department store david jones -37.813313 144.964373 retail department store david jones [retail, department, store, david, jones] retail department store david jones
228 health services medical services mercy private hospital -37.811897 144.984436 health services medical services mercy private... [health, services, medical, services, mercy, p... health services medical services mercy private...
229 mixed use retail/office/carpark anz 'gothic' bank -37.816158 144.961674 mixed use retail office carpark anz gothic bank [mixed, use, retail, office, carpark, anz, got... mixed use retail office carpark anz gothic bank

230 rows × 8 columns

TfidfVectorizer¶

In [25]:
vectorizer = TfidfVectorizer(stop_words='english')

tfidf_matrix = vectorizer.fit_transform(places['corpus_clean'])

Processing user input¶

In [26]:
def user_input(place,user_loc):
    
    user_input_vector = vectorizer.transform([place])
    l1,l2=coordinates(user_loc)
    return user_input_vector,l1,l2

cosine similarity to filter out records which are similar to the user input¶

In [27]:
def get_filtered_places(user_input_vector,tfidf_matrix,places,l1,l2):
    similarities=cosine_similarity(user_input_vector, tfidf_matrix)
    top_ind=np.argsort(similarities[0])[::-1]
    similar_indices=[]
    for i in top_ind:
        if similarities[0][i]>0:
            
            similar_indices.append(i)
    
    relevant_records = places.iloc[similar_indices]
    relevant_records.reset_index(drop=True,inplace=True)
    #Applying haversine distance to filter the records(at max 10) which are within 2km of user's location
    ind=[]
    
    for i,j in relevant_records.iterrows():
        distance=haversine(l1,l2,j['latitude'],j['longitude'])
        if distance<=2 and len(ind)<10:
            ind.append(i)
    relevant_records_filtered = relevant_records.iloc[ind]
    return relevant_records_filtered

===============================================================================================================

Preprocessing the Parking_bays dataset¶

In [28]:
parking_bays
Out[28]:
roadsegmentid kerbsideid roadsegmentdescription latitude longitude lastupdated
0 22730 NaN Park Street between Mason Street and Randall P... -37.836245 144.982021 2022-08-31
1 22730 NaN Park Street between Mason Street and Randall P... -37.835800 144.982115 2022-08-31
2 20013 5701 Lonsdale Street between William Street and Kin... -37.814238 144.955451 2023-10-02
3 20013 23444 Lonsdale Street between William Street and Kin... -37.814271 144.955334 2023-10-02
4 22268 NaN Clowes Street between Anderson Street and Wals... -37.830568 144.984713 2022-08-31
... ... ... ... ... ... ...
19157 22492 NaN Alexandra Avenue between Swan Street Bridge an... -37.827226 144.980441 2022-08-31
19158 22492 NaN Alexandra Avenue between Swan Street Bridge an... -37.827380 144.981004 2022-08-31
19159 22492 NaN Alexandra Avenue between Swan Street Bridge an... -37.826361 144.979266 2022-08-31
19160 22492 NaN Alexandra Avenue between Swan Street Bridge an... -37.826780 144.979662 2022-08-31
19161 22492 NaN Alexandra Avenue between Swan Street Bridge an... -37.825850 144.978719 2022-08-31

19162 rows × 6 columns

In [29]:
parking_bays.shape
Out[29]:
(19162, 6)
In [30]:
parking_bays.isna().sum()
Out[30]:
roadsegmentid                 0
kerbsideid                14149
roadsegmentdescription        0
latitude                      0
longitude                     0
lastupdated                   0
dtype: int64
In [31]:
parking_bays.drop(columns='kerbsideid',inplace=True)
parking_bays.isna().sum()
Out[31]:
roadsegmentid             0
roadsegmentdescription    0
latitude                  0
longitude                 0
lastupdated               0
dtype: int64

Applying haversine distance to filter the parking bays which are within 200m of filtered places of interest¶

In [32]:
def get_filtered_parking(parking_bays,relevant_records_filtered):
    ind=[]
    for i,j in parking_bays.iterrows():
        for m,n in relevant_records_filtered.iterrows():

            distance=haversine(j['latitude'],j['longitude'],n['latitude'],n['longitude'])
            if distance<=0.2 and i not in ind:
                ind.append(i)
    parking_bays_filtered = parking_bays.iloc[ind]
    parking_bays_filtered.reset_index(drop=True,inplace=True)
    return parking_bays_filtered

Displaying all places of interest and filtered places, all parking bays, filtered places and closest parking bays on a map.¶

In [33]:
place_name = input("Enter a place of interest: ").lower()
user_loc=input("Enter your location: ").lower()
user_input_vector,user_l1,user_l2=user_input(place_name,user_loc)
relevant_records_filtered=get_filtered_places(user_input_vector,tfidf_matrix,places,user_l1,user_l2)
parking_bays_filtered=get_filtered_parking(parking_bays,relevant_records_filtered)


map_display1 = folium.Map(location=[places['latitude'].mean(), places['longitude'].mean()], zoom_start=10)

map_display1=create_map(map_display1,places,'feature_name','blue')
map_display1=create_map(map_display1,relevant_records_filtered,'feature_name','green')

legend_html1 = """
    <div style="position: fixed; 
                bottom: 50px; left: 50px; width: 150px; height: 60px; 
                border:2px solid grey; z-index:9999; font-size:14px;
                background-color:white; opacity: 0.8;">
          <p style="text-align:center; margin: 0;"><strong>Legend</strong></p>
          <p style="margin: 0;">All places of interest: <span style="color:lightblue">&#9679;</span></p>
          <p style="margin: 0;">Filtered places: <span style="color:green">&#9679;</span></p>
    </div>
    """
     
title_html1 = """
<h3 style="text-align: center; margin: 10px 0;">All places of interest and filtered places of interest</h3>
"""

map_display1.get_root().html.add_child(folium.Element(legend_html1))
map_display1.get_root().html.add_child(folium.Element(title_html1))

# map_html_places = map_display1._repr_html_()

#-------------------------------------------------------------------
map_display2 = folium.Map(location=[parking_bays['latitude'].mean(), parking_bays['longitude'].mean()], zoom_start=10)

map_display2=create_map(map_display2,parking_bays,'roadsegmentdescription','blue',marker=True)

legend_html2 = """
<div style="position: fixed; 
            bottom: 50px; left: 50px; width: 150px; height:50px; 
            border:2px solid grey; z-index:9999; font-size:14px;
            background-color:white; opacity: 0.8;">
       <p style="text-align:center; margin: 0;"><strong>Legend</strong></p>
       <p style="margin: 0;">Parking Spots: <span style="color:lightblue">&#9679;</span></p>
</div>
"""    
title_html2 = """
<h3 style="text-align: center; margin: 10px 0;">Parking Bays</h3>
"""
map_display2.get_root().html.add_child(folium.Element(legend_html2))
map_display2.get_root().html.add_child(folium.Element(title_html2))

# map_html_parking = map_display2._repr_html_()

#-------------------------------------------------------------------

map_display3 = folium.Map(location=[relevant_records_filtered['latitude'].mean(), relevant_records_filtered['longitude'].mean()], zoom_start=10)

map_display3=create_map(map_display3,parking_bays_filtered,'roadsegmentdescription','orange',marker=True)
map_display3=create_map(map_display3,relevant_records_filtered,'feature_name','blue')

legend_html3 = """
    <div style="position: fixed; 
                bottom: 50px; left: 50px; width: 150px; height: 90px; 
                border:2px solid grey; z-index:9999; font-size:14px;
                background-color:white; opacity: 0.8;">
          <p style="text-align:center; margin: 0;"><strong>Legend</strong></p>
          <p style="margin: 0;">Places of interest: <span style="color:lightblue">&#9679;</span></p>
    </div>
    """
title_html3 = """
<h3 style="text-align: center; margin: 10px 0;">Filtered places and closest parking bays</h3>
"""
    
map_display3.get_root().html.add_child(folium.Element(legend_html3))
map_display3.get_root().html.add_child(folium.Element(title_html3))

# map_html_parking_places = map_display3._repr_html_()
#-------------------------------------------------------------------

# tab1 = widgets.Output()
# tab2 = widgets.Output()
# tab3 = widgets.Output()

# with tab1:
#     display(HTML(map_html_places))

# with tab2:
#     display(HTML(map_html_parking))
    
# with tab3:
#     display(HTML(map_html_parking_places))

# # Create a tab layout
# tabs = widgets.Tab(children=[tab3])
# tabs.set_title(0, 'All places vs filtered places')
# # tabs.set_title(1, 'Parking bays')
# # tabs.set_title(2, 'Filtered places and closest parking')
# display(tabs)
Out[33]:
<branca.element.Element at 0x179d17f70>
In [34]:
display(map_display1)
Make this Notebook Trusted to load map: File -> Trust Notebook
In [35]:
display(map_display2)
Make this Notebook Trusted to load map: File -> Trust Notebook
In [36]:
display(map_display3)
Make this Notebook Trusted to load map: File -> Trust Notebook
References:

SDG Indicators
Economic Development Strategy 2031